package thread;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: wx
 * Date: 2024-01-04
 * Time: 18:40
 */


/**
 *  wait 和 notify
         等待    通知
         和 join 用途类似,多个线程随机调度
         引入 wait 和 notify 就是为了能够从应用层面,干预到多个不同线程代码的执行顺序
         这里的干预,不是影响系统的线程调度策略(内核里调度线程,仍然是无序调度)

         相当于是在应用程序代码中,让后执行的线程,主动放弃被调度的机会,就可以让先执行的线程,先把对应的代码执行完
 */
    /*
     线程饿死的前提条件:
      1.线程之间的调度是无序的
      2.线程一,需要完成当前的工作
    */
/*
  在某一多线程中,线程一反复获取锁,但又无法完成实质性的逻辑
  其他线程无法拿到锁,这一情况就被称为"线程饿死"
  像线程饥饿这样的问题,属于是"概率性"的事件
  不像死锁,一旦出现,线程必挂
  但是也会极大的影响其他线程运行

  这种情况也属于是bug.虽然没有死锁那么严重,但是也是需要处理的
  这里的关键在于,第一个线程,在他发现自己要执行的逻辑,前提条件不具备
  在这个情况下,线程一就应该主动放弃锁竞争/主动放弃去cpu上执行调度(进入阻塞)
  一直等到条件满足了之后在进行阻塞解除,参与锁竞争

  此时,就可以使用 wait 和 notify 来完成这个过程了
  让线程一看当前条件是否满足,不满足就 wait
  其他线程如果让条件满足之后,再通过 notify 唤醒线程一

  wait 内部会进行三件事:                    join 是等待另一个线程执行完,才继续执行
  1.释放锁                                wait 是等待另一个线程通过 notify 进行通知
  2进入阻塞等待                                        (不要求另一个线程必须执行完)
  3当其他线程调用notify的时候
   wait就会解除阻塞,并且重新获取到锁

   阻塞,产生的原因有好几种:
   1.sleep TIMED_WAITING
   2.join/wait WAITING
   3.synchronized BLOCKED

   1)wait 和 notify 是通过 object 对象联系起来的
   必须是一致的对象才能唤醒
   2)notifyAll 唤醒这个对象上所有等待的线程

   wait和sleep之间的区别
   都是时间到,就继续执行,解除阻塞了

   wait 和 sleep 都可以被提前唤醒(虽然时间没到,但是也可能提前唤醒)
   wait通过 notify唤醒
   sleep通过 interrupt 唤醒

                                           wait大部分情况下,都是在超时时间之内就被唤醒了,对于sleep,大部分情况下都是期望能够准时被唤醒,
                                           少数极端情况下通过特殊手段提前唤醒他
   使用wait,最主要的目标,一定是不知道要等多少时间的前提下使用的.所谓超时时间,其实是"兜底的"
   使用sleep,一定是知道多少时间的前提下使用的,虽然能提前唤醒,但是通过异常唤醒,这个操作不应该作为"正常的业务流程"
                                      (通过异常唤醒,说明程序应该是出现了一些特殊情况了)

*/
public class ThreadDemo23 {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();

        synchronized (object){ //每个对象里边都有一把锁
            System.out.println("wait之前");
            object.wait();            // wait 调用的对象必须要和 synchronized 中的锁对象是一致的!!!
           //结果就是代码在这里了阻塞      //因此,wait 解锁必须是解 object 的锁
                                      //后续,wait 被唤醒之后,重新获取锁,当然还是获取到 object 的锁
            System.out.println("wait之后");
            //如果有其他线程也尝试获取锁. wait 被唤醒之后,也是要重新参与到锁竞争当中去
        }

    }
    public static void main1(String[] args) throws InterruptedException {
        Object object = new Object();

        object.wait();//直接调用wait ,会出现异常 synchronized 也叫监视器锁,"锁对象",就像监控一样 wait 一进来先要释放锁 释放锁的前提是得先有锁
                      //wait 必须放到 synchronized 里面使用
    }
}
